﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Timers;
using Engine;

namespace GameOfCoins
{
	public partial class GameMainFrame : Form
	{
		private string[]	m_strWorldFiles;
		private int			m_iActiveWorld;
		private int			m_iP1ID;
		private int			m_iP2ID;
		private int			m_iActivePlayer;

		////////// ENGINE
		private CWorldCore	m_oWorldCore;
		private CPlayerCore	m_oPlayerCore;
		private bool		m_bRunning;

		////////// MOVEMENT
		private bool m_bMoveRight;
		private bool m_bMoveLeft;
		private bool m_bMoveUp;
		private bool m_bMoveDown;
		private System.Timers.Timer m_oTimer;

		public GameMainFrame()
		{
			InitializeComponent();

			m_bMoveRight	= false;
			m_bMoveLeft		= false;
			m_bMoveUp		= false;
			m_bMoveDown		= false;
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// UTILITIES

		//Init members and make controls visible (mandatory!)
		//@ KR / 2014.06.25
		public void Init(string[] strWorldFiles, int iP1ID, int iP2ID)
		{
			m_strWorldFiles = strWorldFiles;
			m_iActiveWorld	= 0;
			m_iActivePlayer = 1;		//Player 1 will start
			m_bRunning		= false;
			m_iP1ID			= iP1ID;
			m_iP2ID			= iP2ID;

			//Start engine
			m_oWorldCore	= new CWorldCore();
			m_oPlayerCore	= new CPlayerCore();

			//Set players here. So they will keep there points in between matches
			m_oPlayerCore.CreatePlayer(1, m_iP1ID);
			m_oPlayerCore.CreatePlayer(2, m_iP2ID);

			//Make controls visible
			//TODO: Draw picturebox border after engine init (look better)
			pbPlayboard.Visible		= true;
			pnlPlayer1.Visible		= true;
			pnlPlayer2.Visible		= true;
			lblActPlayer.Visible	= true;

			//Set picturebox images
			pbP1Coin.Image = Engine.Properties.Resources.coin;
			pbP2Coin.Image = Engine.Properties.Resources.coin;
			pbP1Stamina.Image = Engine.Properties.Resources.endurance;
			pbP2Stamina.Image = Engine.Properties.Resources.endurance;
			pbP1Player.Image = new Bitmap(m_oPlayerCore.GetPlayerImage(1), 48, 48);
			pbP2Player.Image = new Bitmap(m_oPlayerCore.GetPlayerImage(2), 48, 48);

			//Start first game
			StartGame();
		}

		//Start game animation
		//@ KR / 2014.06.25
		private void StartAnimation()
		{
			m_bRunning = true;
			CAnimationCore.StartPlayboardRenderer();
		}

		//Stop game animation
		//@ KR / 2014.06.25
		private void StopAnimation()
		{
			m_bRunning = false;
			CAnimationCore.StopPlayboardRenderer();
		}

		//Dispose all allocated resources
		//@ KR / 2014.06.29
		private void DisposeResources()
		{
			m_oPlayerCore.Dispose();

			pbP1Coin.Image.Dispose();
			pbP2Coin.Image.Dispose(); 
			pbP1Stamina.Image.Dispose();
			pbP2Stamina.Image.Dispose();
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// GAME LOGIC

		//Start new game
		//@ KR / 2014.06.25
		private void StartGame()
		{
			int		iWorldWidth     = 0;
			int		iWorldHeight    = 0;
			Point	ptP1Start		= new Point(0, Const.GRIDS_YAXIS-1);
			Point	ptP2Start		= new Point(Const.GRIDS_XAXIS-1, Const.GRIDS_YAXIS-1);

			//Load world
			m_oWorldCore.LoadWorld(m_strWorldFiles[m_iActiveWorld++]);

			//Create players
			m_oPlayerCore.SetWorld(ref m_oWorldCore);
			m_oPlayerCore.SetStartPos(1, ptP1Start);
			m_oPlayerCore.SetStartPos(2, ptP2Start);

			//Set initial stamina
			m_oPlayerCore.GenerateStamina(m_iActivePlayer);

			//Resize control
			m_oWorldCore.GetWorldDimensions(ref iWorldWidth, ref iWorldHeight);
			pbPlayboard.Width		= iWorldWidth;
			pbPlayboard.Height		= iWorldHeight;
			CUtilities.CenterPictureBox(pbPlayboard);
			CUtilities.CenterLabel(lblActPlayer);

			//Animation
			CAnimationCore.s_pbPlayboard	= pbPlayboard;

			//Set initial point and stamina values
			lblP1Coins.Text = m_oPlayerCore.GetPoints(1).ToString();			//P1 points
			lblP1Stamina.Text = m_oPlayerCore.GetStamina(1).ToString();			//P1 stamina
			lblP2Coins.Text = m_oPlayerCore.GetPoints(2).ToString();			//P2 points
			lblP2Stamina.Text = m_oPlayerCore.GetStamina(2).ToString();			//P2 stamina

			//For automatic and on demand updates, set lables to player core
			m_oPlayerCore.SetLabel(lblP1Coins, lblP2Coins, lblP1Stamina, lblP2Stamina);

			//Start Game
			m_oPlayerCore.StartGame();
			StartAnimation();

			//Start timer
			m_oTimer          = new System.Timers.Timer(20);
			m_oTimer.Elapsed += new ElapsedEventHandler(MoveTimeEvent);
			m_oTimer.Start();
		}

		//End game
		//@ KR / 2014.06.25
		private void EndGame(bool bTerminate)
		{
			//Reset movement
			m_bMoveRight = false;
			m_bMoveLeft	 = false;
			m_bMoveUp    = false;
			m_bMoveDown  = false;	

			//Switch player and reset stamina to 0
			if(!bTerminate)
			{
				SwitchPlayer();
				m_oPlayerCore.ResetStamina(1);
				m_oPlayerCore.ResetStamina(2);
			}

			StopAnimation();
			m_oTimer.Stop();
			m_oTimer = null;

			CAnimationCore.Clear();
			m_oPlayerCore.EndGame();
		
			m_oWorldCore.DeleteWorld();
		}

		//Switch current active player
		//@ KR / 2014.06.28
		private void SwitchPlayer()
		{
			//Only allow outside of any motion
			if(!m_oPlayerCore.IsAnimated(m_iActivePlayer))
			{
				if(!m_oPlayerCore.HasSolidStand(m_iActivePlayer))
					m_oPlayerCore.FreeFall(m_iActivePlayer, false);

				if(m_iActivePlayer == 1)
					m_iActivePlayer = 2;
				else
					m_iActivePlayer = 1;

				m_oPlayerCore.GenerateStamina(m_iActivePlayer);

				lblActPlayer.Text = "Spieler " + m_iActivePlayer.ToString();
				CUtilities.CenterLabel(lblActPlayer);

				//Update player stats
				switch(m_iActivePlayer)
				{
					case 1 :
						lblP1Coins.Text = m_oPlayerCore.GetPoints(1).ToString();
						lblP1Stamina.Text = m_oPlayerCore.GetStamina(1).ToString();
						break;
					case 2 :
						lblP2Coins.Text = m_oPlayerCore.GetPoints(2).ToString();
						lblP2Stamina.Text = m_oPlayerCore.GetStamina(2).ToString();
						break;
				}
			}
		}

		//Check if all coins are collected and end game resp. start next world
		//@ KR / 2014.06.29
		private void CheckEndGame()
		{
			if(m_oWorldCore.GetCoins() == 0)
			{
				//End current game
				EndGame(false);

				Highscore oHighscore = new Highscore(m_oPlayerCore);
				oHighscore.ShowDialog();

				//Start next
				if(m_iActiveWorld < m_strWorldFiles.Length)
				{
					StartGame();
				}
				else
				{
					Close();
				}
			}
		}

		//Timer event responsible for player movement
		// - Timer is used to overcome the delay when key is long pressed
		//@ KR / 2014.07.07
		private void MoveTimeEvent(object source, ElapsedEventArgs e)
		{   
			if(m_bMoveRight || m_bMoveLeft || m_bMoveUp || m_bMoveDown)
			{
				if(m_bMoveRight)
					m_oPlayerCore.MoveRight(m_iActivePlayer);
				else if(m_bMoveLeft)
					m_oPlayerCore.MoveLeft(m_iActivePlayer);
				else if(m_bMoveUp)
					m_oPlayerCore.MoveUp(m_iActivePlayer);
				else if(m_bMoveDown)
					m_oPlayerCore.FreeFall(m_iActivePlayer, false);

				//Kick player
				// NOTE: A falling player can not kick another player on his path down
				if(m_oPlayerCore.OverOpponent(m_iActivePlayer))
					m_oPlayerCore.Kick(m_iActivePlayer);
			}
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// EVENTS

		//When first opened, show game setup
		// - Close game if setup gets cancled
		//@ KR / 2014.06.25
		private void GameMainFrame_Shown(object sender, EventArgs e)
		{
			GameSetup oSetup = new GameSetup(this);
			if(oSetup.ShowDialog() == DialogResult.Cancel)
				Close();
		}

		//Capture pressed keys
		// - Player movement
		// - Pause menu
		//@ KR / 2014.06.25
		private void GameMainFrame_KeyDown(object sender, KeyEventArgs e)
		{
			//Pause menu
			if(e.KeyCode == Keys.Escape)
			{
				PauseMenu oPauseMenu = new PauseMenu(this);
				StopAnimation();
				if(oPauseMenu.ShowDialog() == DialogResult.OK)	//Closed by pression "weiter"
					StartAnimation();
				else	//Quit game
				{
					EndGame(true);
					DisposeResources();
					Close();
				}
			}

			if(m_bRunning)
			{
				////////// Switch player (on Space and possible)
				if(e.KeyCode == Keys.Space)
				{
					SwitchPlayer();
					return;
				}

				////////// Movement (automatic update of stats since labels have been provided to core)
				//Reset movement bools
				m_bMoveRight	= false;
				m_bMoveLeft		= false;
				m_bMoveUp		= false;
				m_bMoveDown		= false;

				//Set bools
				if(e.KeyCode == Keys.Right)
					m_bMoveRight = true;
				else if(e.KeyCode == Keys.Left)
					m_bMoveLeft = true;
				else if(e.KeyCode == Keys.Up)
					m_bMoveUp = true;
				else if(e.KeyCode == Keys.Down)
					m_bMoveDown = true;
			}
		}

		//Capture key up
		// - Reset movement bools
		//@ KR / 2014.07.07
		private void GameMainFrame_KeyUp(object sender, KeyEventArgs e)
		{
			m_bMoveRight	= false;
			m_bMoveLeft		= false;
			m_bMoveUp		= false;
			m_bMoveDown		= false;
		}

		private void lblP1Coins_TextChanged(object sender, EventArgs e)
		{
			CheckEndGame();
		}
		private void lblP2Coins_TextChanged(object sender, EventArgs e)
		{
			CheckEndGame();
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// CTRLS
	}
}
